﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using HeartLess.Core;
using HeartLess.Managers;

namespace HeartLess.GameObjects
{
    public class Demon : Enemy
    {
        private Animation _animation;
        private AssetManager.ANIMATIONS _walkAnimation;
        private AssetManager.ANIMATIONS _attackAnimation;
        private AssetManager.ANIMATIONS _idleAnimation;

        private int _idleFrameCount;
        private int _idleFrameTime;

        private int _attackFrameCount;
        private int _attackFrameTime;

        private int _walkFrameCount;
        private int _walkFrameTime;

        private Player _target;
        private Vector2 _targetDirection;

        private int _timeUntilNextSearch;

        private const int SEARCH_FREQUENCY = 2000; //ms
        private static readonly Vector2 VELOCITY = new Vector2(200, 0);

        private int _attackDelay;
        private bool _isAttacking;

        private const int SPAWN_PROXIMITY = 400;
        private const int MAX_ATTACK_DELAY = 1000;//ms

        public const string SKIN_GREEN_SLIME = "GreenSlime";
        public const string SKIN_RED_SLIME = "RedSlime";
        public const string SKIN_BLUE_SLIME = "BlueSlime";
        public const string SKIN_SOLDIER = "Soldier";

        private enum Animations
        {
            IDLE,
            RUN_LEFT,
            RUN_RIGHT,
            ATTACK_LEFT,
            ATTACK_RIGHT
        }

         private Animations _currentAnimation;
         private Animations CurrentAnimation
         {
             set
             {
                 if (value == _currentAnimation) return;

                 switch (value)
                 {
                     case Animations.IDLE:
                         StartIdleAnimation();
                         break;

                     case Animations.RUN_LEFT:
                         StartRunningAnimation(true);
                         break;

                     case Animations.RUN_RIGHT:
                         StartRunningAnimation(false);
                         break;

                     case Animations.ATTACK_LEFT:
                         StartAttackAnimation(true);
                         break;

                     case Animations.ATTACK_RIGHT:
                         StartAttackAnimation(false);
                         break;
                 }

                 _currentAnimation = value;
             }

         }

        public Demon(Point spawnPoint, Player target, string skin)
            : base(spawnPoint)
        {
            switch (skin)
            {
                case SKIN_SOLDIER:
                    _walkAnimation = AssetManager.ANIMATIONS.SOLDIER_WALK;
                    _walkFrameCount = 25;
                    _walkFrameTime = 32;
                    
                    _idleAnimation = AssetManager.ANIMATIONS.SOLDIER_IDLE;
                    _idleFrameCount = 47;
                    _idleFrameTime = 32;

                    _attackAnimation = AssetManager.ANIMATIONS.SOLDIER_ATTACK;
                    _attackFrameCount = 25;
                    _attackFrameTime = 18;
                    break;

                case SKIN_BLUE_SLIME:
                    _walkAnimation = AssetManager.ANIMATIONS.BLUE_SLIME_WALK;
                    _walkFrameCount = 25;
                    _walkFrameTime = 28;

                    _attackAnimation = AssetManager.ANIMATIONS.BLUE_SLIME_ATTACK;
                    _attackFrameCount = 53;
                    _attackFrameTime = 28;

                    _idleAnimation = AssetManager.ANIMATIONS.BLUE_SLIME_IDLE;
                    _idleFrameCount = 25;
                    _idleFrameTime = 28;
                    break;

                case SKIN_RED_SLIME:
                    _walkAnimation = AssetManager.ANIMATIONS.RED_SLIME_WALK;
                    _walkFrameCount = 25;
                    _walkFrameTime = 28;

                    _attackAnimation = AssetManager.ANIMATIONS.RED_SLIME_ATTACK;
                    _attackFrameCount = 53;
                    _attackFrameTime = 28;

                    _idleAnimation = AssetManager.ANIMATIONS.RED_SLIME_IDLE;
                    _idleFrameCount = 25;
                    _idleFrameTime = 28;
                    break;

                case SKIN_GREEN_SLIME:
                default:
                    _walkAnimation = AssetManager.ANIMATIONS.GREEN_SLIME_WALK;
                    _walkFrameCount = 25;
                    _walkFrameTime = 28;

                    _attackAnimation = AssetManager.ANIMATIONS.GREEN_SLIME_ATTACK;
                    _attackFrameCount = 53;
                    _attackFrameTime = 28;

                    _idleAnimation = AssetManager.ANIMATIONS.GREEN_SLIME_IDLE;
                    _idleFrameCount = 25;
                    _idleFrameTime = 28;
                    break;

            }

            _currentAnimation = Animations.IDLE;
            StartIdleAnimation();

            GravityEnabled = true;

            _target = target;
            SearchForPlayer();
        }


        protected override void onMove()
        {
            _animation.Location = this.Location;            
        }

        public override void Update(GameTime gameTime)
        {
            if (IsSpawned)
            {
                base.Update(gameTime);

                _timeUntilNextSearch -= gameTime.ElapsedGameTime.Milliseconds;

                if (_timeUntilNextSearch < 0)
                {
                    SearchForPlayer();
                }

                _attackDelay -= gameTime.ElapsedGameTime.Milliseconds;

                bool moved = tryMove(_targetDirection);

                if (_isAttacking == false)
                {
                    if (moved)
                    {
                        CurrentAnimation = (_targetDirection == VELOCITY) ? Animations.RUN_LEFT
                                                                          : Animations.RUN_RIGHT;
                    }
                    else
                    {
                        CurrentAnimation = Animations.IDLE;
                    }
                }

                _animation.Update(gameTime);
            }
            else
            {
                if (_target.Location.X > this.Location.X - SPAWN_PROXIMITY)
                {
                    IsSpawned = true;
                }
            }
        }

        protected override void handleCollision(CollidableGameObject collidedObject)
        {
            if (collidedObject == _target)
            {
                if (_attackDelay < 0)
                {
                    _isAttacking = true;

                    if (isTargetToLeft())
                    {
                        CurrentAnimation = Animations.ATTACK_LEFT;
                    }
                    else
                    {
                        CurrentAnimation = Animations.ATTACK_RIGHT;
                    }

                    HeartRateModifier.ChangeHeartRateFactor(_target, .3f, 2f);

                    _attackDelay = MAX_ATTACK_DELAY;
                }

                SearchForPlayer();
            }
        }

        public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
        {
            if (IsSpawned)
                _animation.Draw(spriteBatch);
        }

        private void StartIdleAnimation()
        {
            Texture2D idleAnimationTexture = AssetManager.GetAnimationTexture(_idleAnimation);
            _animation = new Animation(idleAnimationTexture, _idleFrameCount, _idleFrameTime);
            _animation.Location = this.Location;
        }

        private void StartRunningAnimation(bool isRunningLeft)
        {
            Texture2D runningAnimationTexture = AssetManager.GetAnimationTexture(_walkAnimation);
            _animation = new Animation(runningAnimationTexture, _walkFrameCount, _walkFrameTime);
            _animation.IsFlippedHorizonally = isRunningLeft;
            _animation.Location = this.Location;
        }

        private void StartAttackAnimation(bool isAttackingLeft)
        {
            Texture2D attackAnimationTexture = AssetManager.GetAnimationTexture(_attackAnimation);
            _animation = new Animation(attackAnimationTexture, _attackFrameCount, _attackFrameTime);
            _animation.Location = this.Location;
            _animation.RepeatEnabled = false;
            _animation.IsFlippedHorizonally = isAttackingLeft;
            _animation.OnAnimationCompleted = AttackAnimationCompleted;
        }

        private void AttackAnimationCompleted()
        {
            _isAttacking = false;
            CurrentAnimation = Animations.IDLE;
        }

        private void SearchForPlayer()
        {
            if ((_target.Location - this.Location).X > 0)
            {
                _targetDirection = VELOCITY;
            }
            else
            {
                _targetDirection = -VELOCITY;
            }

            _timeUntilNextSearch = SEARCH_FREQUENCY;
        }

        private bool isTargetToLeft()
        {
            return (_targetDirection == VELOCITY);
        }
    }
}
